<template>
	<el-dialog v-dialogDrag :title="title"  top="5vh"
	 :close-on-click-modal="false"
	 :close-on-press-escape="false"
	:visible.sync="visible" width="50%" height="70%" :before-close="handleClose">
		<div class="chat-video">
			<div class="chat-video-box">
				<div class="chat-video-friend" v-loading="loading" element-loading-text="等待对方接听..." element-loading-spinner="el-icon-loading"
				 element-loading-background="rgba(0, 0, 0, 0.5)">
					<head-image class="friend-head-image" :id="this.friend.id" :size="80" :url="this.friend.headImage"></head-image>
					<video ref="friendVideo" autoplay=""></video>
				</div>
				<div class="chat-video-mine">
					<video  ref="mineVideo" autoplay=""></video>
				</div>
			</div>
			<div class="chat-video-controllbar">
				<div v-show="state=='CONNECTING'" title="取消呼叫" class="icon iconfont icon-phone-reject reject" style="color: red;"
				 @click="cancel()"></div>
				<div v-show="state=='CONNECTED'" title="挂断" class="icon iconfont icon-phone-reject reject" style="color: red;"
				 @click="handup()"></div>
			</div>
		</div>
	</el-dialog>

</template>

<script>
	import HeadImage from '../common/HeadImage.vue';
	
	export default {
		name: 'chatVideo',
		components: {HeadImage},
		props: {
			visible: {
				type: Boolean
			},
			friend: {
				type: Object
			},
			master: {
				type: Boolean
			},
			offer: {
				type: Object
			}
		},
		data() {
			return {
				stream: null,
				audio: new Audio(),
				loading: false,
				peerConnection: null,
				videoTime: 0,
				videoTimer: null,
				state: 'NOT_CONNECTED',
				candidates: [],
				configuration: {
					iceServers: []
				}
			}
		},
		methods: {
			init() {
				if (!this.hasUserMedia() || !this.hasRTCPeerConnection()) {
					this.$message.error("您的浏览器不支持WebRTC");
					if (!this.master) {
						this.sendFailed("对方浏览器不支持WebRTC")
					}
					return;
				}
				// 打开摄像头
				this.openCamera((stream) => {
					// 初始化webrtc连接
					this.setupPeerConnection(stream);
					if (this.master) {
						// 发起呼叫
						this.call();
					} else {
						// 接受呼叫
						this.accept(this.offer);
					}
				});
			},
			openCamera(callback) {
				navigator.getUserMedia({
						video: true,
						audio: true
					},
					(stream) => {
						this.stream = stream;
						console.log(this.stream)
						this.$refs.mineVideo.srcObject = stream;
						this.$refs.mineVideo.muted = true;
						callback(stream)
					},
					(error) => {
						this.$message.error("打开摄像头失败:" + error);
						callback()
					});
			},
			closeCamera() {
				if (this.stream) {
					this.stream.getTracks().forEach((track) => {
						track.stop();
					});
					this.$refs.mineVideo.srcObject = null;
					this.stream = null;
				}

			},
			setupPeerConnection(stream) {
				this.peerConnection = new RTCPeerConnection(this.configuration);
				this.peerConnection.ontrack = (e) => {
					this.$refs.friendVideo.srcObject = e.streams[0];
				};
				this.peerConnection.onicecandidate = (event) => {
					if (event.candidate) {
						if (this.state == 'CONNECTED') {
							// 已连接,直接发送
							this.sendCandidate(event.candidate);
						} else {
							// 未连接,缓存起来，连接后再发送
							this.candidates.push(event.candidate)
						}
					}
				}
				if (stream) {
					stream.getTracks().forEach((track) => {
						this.peerConnection.addTrack(track, stream);
					});
				}
				this.peerConnection.oniceconnectionstatechange = (event) => {
					let state = event.target.iceConnectionState;
					console.log("ICE connection status changed : " + state)
					if(state == 'connected'){
						this.resetTime();
					}
				};

			},
			handleMessage(msg) {
				if (msg.type == this.$enums.MESSAGE_TYPE.RTC_ACCEPT) {
					this.peerConnection.setRemoteDescription(new RTCSessionDescription(JSON.parse(msg.content)));
					// 关闭等待提示
					this.loading = false;
					// 状态为连接中
					this.state = 'CONNECTED';
					// 停止播放语音
					this.audio.pause();
					// 发送candidate
					this.candidates.forEach((candidate) => {
						this.sendCandidate(candidate);
					})
				}
				else if (msg.type == this.$enums.MESSAGE_TYPE.RTC_REJECT) {
					this.$message.error("对方拒绝了您的视频请求");
					this.close();
				}
				else if (msg.type == this.$enums.MESSAGE_TYPE.RTC_FAILED) {
					this.$message.error(msg.content)
					this.close();
				}
				else if (msg.type == this.$enums.MESSAGE_TYPE.RTC_CANDIDATE) {
					this.peerConnection.addIceCandidate(new RTCIceCandidate(JSON.parse(msg.content)));
				}
				else if (msg.type == this.$enums.MESSAGE_TYPE.RTC_HANDUP) {
					this.$message.success("对方挂断了视频通话");
					this.close();
				}
			},
			call() {
				this.peerConnection.createOffer((offer) => {
						this.peerConnection.setLocalDescription(offer);
						this.$http({
							url: `/webrtc/private/call?uid=${this.friend.id}`,
							method: 'post',
							data: JSON.stringify(offer)
						}).then(() => {
							this.loading = true;
							this.state = 'CONNECTING';
							this.audio.play();
						});
					},
					(error) => {
						this.$message.error(error);
					});

			},
			accept(offer) {
				this.peerConnection.setRemoteDescription(new RTCSessionDescription(offer));
				this.peerConnection.createAnswer((answer) => {
						this.peerConnection.setLocalDescription(answer);
						this.$http({
							url: `/webrtc/private/accept?uid=${this.friend.id}`,
							method: 'post',
							data: JSON.stringify(answer)
						})
						this.state = 'CONNECTED';
					},
					(error) => {
						this.$message.error(error);
					});

			},
			handup() {
				this.$http({
					url: `/webrtc/private/handup?uid=${this.friend.id}`,
					method: 'post'
				})
				this.close();
				this.$message.success("已挂断视频通话")
			},
			cancel() {
				this.$http({
					url: `/webrtc/private/cancel?uid=${this.friend.id}`,
					method: 'post'
				})
				this.close();
				this.$message.success("已停止呼叫视频通话")
			},
			sendFailed(reason) {
				this.$http({
					url: `/webrtc/private/failed?uid=${this.friend.id}&reason=${reason}`,
					method: 'post'
				})
			},
			sendCandidate(candidate) {
				this.$http({
					url: `/webrtc/private/candidate?uid=${this.friend.id}`,
					method: 'post',
					data: JSON.stringify(candidate)
				})
			},
			close() {
				this.$emit("close");
				this.closeCamera();
				this.loading = false;
				this.state = 'NOT_CONNECTED';
				this.videoTime = 0;
				this.videoTimer && clearInterval(this.videoTimer);
				this.audio.pause();
				this.candidates = [];
				this.$store.commit("setUserState", this.$enums.USER_STATE.FREE);
				this.$refs.friendVideo.srcObject = null;
				this.peerConnection.close();
				this.peerConnection.onicecandidate = null;
				this.peerConnection.onaddstream = null;
			},
			resetTime(){
				this.videoTime = 0;
				this.videoTimer && clearInterval(this.videoTimer);
				this.videoTimer = setInterval(()=>{
					this.videoTime++;
				},1000)
			},
			handleClose() {
				if (this.state == 'CONNECTED') {
					this.handup()
				} else if (this.state == 'CONNECTING') {
					this.cancel();
				} else {
					this.close();
				}
			},
			hasUserMedia() {
				navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia ||
					navigator.msGetUserMedia;
				return !!navigator.getUserMedia;
			},
			hasRTCPeerConnection() {
				window.RTCPeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection;
				window.RTCSessionDescription = window.RTCSessionDescription || window.webkitRTCSessionDescription || window.mozRTCSessionDescription;
				window.RTCIceCandidate = window.RTCIceCandidate || window.webkitRTCIceCandidate || window.mozRTCIceCandidate;
				return !!window.RTCPeerConnection;
			},
			initAudio(){
				let url = require(`@/assets/audio/call.wav`);
				this.audio.src = url;
				this.audio.loop = true;
			},
			initICEServers(){
				this.$http({
					url: '/webrtc/private/iceservers',
					method: 'get'
				}).then((servers) => {
					this.configuration.iceServers = servers;
				})
			}
			
		},
		watch: {
			visible: {
				handler(newValue, oldValue) {
					if (newValue) {
						this.init();
						// 用户忙状态
						this.$store.commit("setUserState", this.$enums.USER_STATE.BUSY);
					}
				}
			}
		},
		computed: {
			title() {
				let strTitle  = `视频聊天-${this.friend.nickName}`;
				if(this.state == 'CONNECTED'){
					strTitle += `(${this.currentTime})`;
				}else if(this.state == 'CONNECTING'){
					strTitle += `(呼叫中)`;
				}
				return strTitle;
			},
			currentTime(){
				let currentTime = 0;
				if(this.state == 'CONNECTED' && this.videoTime){
					 currentTime = Math.floor(this.videoTime);
				}
				let min = Math.floor(currentTime/60);
				let sec = currentTime%60;
				let strTime = min<10?"0":"";
				strTime += min;
				strTime += ":"
				strTime += sec<10?"0":"";
				strTime += sec;
				return strTime;
			}
		},
		mounted() {
			this.initAudio();
			this.initICEServers();
		}
	}
</script>

<style lang="scss" scoped>
	.chat-video {
		position: relative;
		
		.chat-video-box {
			position: relative;
			border: #4880b9 solid 1px;
			background-color: #eeeeee;
			
			.chat-video-friend {
				height: 70vh;
				.friend-head-image {
					position: absolute;
				}

				video {
					width: 100%;
					height: 100%;
					object-fit: fill;
				}
			}

			.chat-video-mine {
				position: absolute;
				z-index: 99999;
				width: 25vh;
				right: 0;
				bottom: 0;
				box-shadow: 0px 0px  5px #ccc;	
				background-color: #cccccc;
				video {
					width: 100%;
				}
			}
		}

		.chat-video-controllbar {
			display: flex;
			justify-content: space-around;
			padding: 10px;

			.icon {
				font-size: 50px;
				cursor: pointer;
			}
		}
	}
</style>
